#include "esp_log.h"
#include "epd_spi.h"
#include "epd_driver.h"

#define EPD_DRIVER_TAG "EPD Driver"

static void epd_reset(void)
{
  epd_gpio_write(EPD_RST_PIN, 1);
  epd_delay_ms(200);
  epd_gpio_write(EPD_RST_PIN, 0);
  epd_delay_ms(2);
  epd_gpio_write(EPD_RST_PIN, 1);
  epd_delay_ms(200);
}

void epd_send_command(uint8_t command)
{
  epd_gpio_write(EPD_DC_PIN, 0);
  epd_gpio_write(EPD_CS_PIN, 0);
  epd_spi_write_byte(command);
  epd_gpio_write(EPD_CS_PIN, 1);
}

void epd_send_data(uint8_t data)
{
  epd_gpio_write(EPD_DC_PIN, 1);
  epd_gpio_write(EPD_CS_PIN, 0);
  epd_spi_write_byte(data);
  epd_gpio_write(EPD_CS_PIN, 1);
}

void epd_read_busy(void)
{
  uint8_t busy;
  ESP_LOGI(EPD_DRIVER_TAG, "e-Paper busy\r\n");
  do
  {
    busy = epd_gpio_read(EPD_BUSY_PIN);
    busy = !(busy & 0x01);
    epd_delay_ms(10);
  } while (busy);
  ESP_LOGI(EPD_DRIVER_TAG, "e-Paper busy release\r\n");
}

void epd_display(void)
{
  epd_send_command(0x04); // POWER ON
  epd_read_busy();
  epd_send_command(0x12); // display refresh
  epd_delay_ms(10);
  epd_read_busy();
}

void epd_init(void)
{
  epd_spi_init();

  epd_module_init();

  epd_reset();

  epd_send_command(0x01); // POWER_SETTING
  epd_send_data(0x37);
  epd_send_data(0x00);

  epd_send_command(0x00); // PANEL_SETTING
  epd_send_data(0xCF);
  epd_send_data(0x08);

  epd_send_command(0x30); // PLL_CONTROL
  epd_send_data(0x3A);    // PLL:  0-15:0x3C, 15+:0x3A

  epd_send_command(0x82); // VCM_DC_SETTING
  epd_send_data(0x28);    // all temperature  range

  epd_send_command(0x06); // BOOSTER_SOFT_START
  epd_send_data(0xc7);
  epd_send_data(0xcc);
  epd_send_data(0x15);

  epd_send_command(0x50); // VCOM AND DATA INTERVAL SETTING
  epd_send_data(0x77);

  epd_send_command(0x60); // TCON_SETTING
  epd_send_data(0x22);

  epd_send_command(0x65); // FLASH CONTROL
  epd_send_data(0x00);

  epd_send_command(0x61);               // TCON_RESOLUTION
  epd_send_data(EPD_7IN5BC_WIDTH >> 8); // source 640
  epd_send_data(EPD_7IN5BC_WIDTH & 0xff);
  epd_send_data(EPD_7IN5BC_HEIGHT >> 8); // gate 384
  epd_send_data(EPD_7IN5BC_HEIGHT & 0xff);

  epd_send_command(0xe5); // FLASH MODE
  epd_send_data(0x03);
}

void epd_clear(void)
{
  uint16_t Width, Height;
  Width = (EPD_7IN5BC_WIDTH % 8 == 0) ? (EPD_7IN5BC_WIDTH / 8) : (EPD_7IN5BC_WIDTH / 8 + 1);
  Height = EPD_7IN5BC_HEIGHT;

  epd_send_command(0x10);
  for (uint16_t j = 0; j < Height; j++)
  {
    for (uint16_t i = 0; i < Width; i++)
    {
      for (uint8_t k = 0; k < 4; k++)
      {
        epd_send_data(0x33);
      }
    }
  }

  epd_display();
}

void epd_sleep(void)
{
  epd_send_command(0x02); // POWER_OFF
  epd_read_busy();
  epd_send_command(0x07); // DEEP_SLEEP
  epd_send_data(0XA5);
}

void epd_exit()
{
  // epd_clear();
  epd_module_exit();
}